<template>
  <a-spin :spinning="loading" class="tree-container">
    <a-input v-model="searchValue" @change="handleSearch" style="width:100%;margin-bottom:20px;"
      :placeholder="placeholder">
      <ry-icon slot="prefix" type="icon-sousuo"></ry-icon>
    </a-input>
    <a-tree v-if="treeData.length>0" :tree-data="treeData" :checkStrictly="true"
      v-model="checkedKeyList" @select="handleNodeClick" @check="handleTreeCheck"
      @expand="handleExpand" :expandedKeys="expandedKeys" :checkable="checkable"
      :replaceFields="replaceFields" draggable @dragenter="onDragEnter" @drop="onDrop">
      <ry-icon slot="switcherIcon" type="icon-xiala" />
      <template slot="custom" slot-scope="item">
        <div class="flex-between">
          <div class="input-container">
            <a-input v-model="name" v-if="editId===item.id" class="input-contant"
              placeholder="请输入分类名称，enter确定" v-focus @blur="handleCancel"
              @keydown.enter.native="handleCheck" @change="onChangeItem($event,item)"></a-input>
            <a-tooltip v-else :title="item.name" placement="topLeft"><span>{{item.name}}</span>
            </a-tooltip>
          </div>
          <div v-if="showHandle" style="margin-left:4px" class="icon-container">
            <a-space>
              <ry-icon v-if="editId!==item.id" type="icon-bianji"
                @click="handleEdit({id:item.id,name:item.name})">
              </ry-icon>
              <a-dropdown v-if="editId!==item.id" :trigger="['click']">
                <ry-icon type="icon-tianjia-lvse">
                </ry-icon>
                <template #overlay>
                  <a-menu>
                    <a-menu-item key="1" @click="handleAdd('0',item)">添加同级分类</a-menu-item>
                    <a-menu-item key="2" @click="handleAdd('1',item)">添加子级分类</a-menu-item>
                  </a-menu>
                </template>
              </a-dropdown>
              <ry-icon v-if="editId!==item.id" type="icon-shangchu" @click="handleDelete(item)">
              </ry-icon>
            </a-space>
          </div>
        </div>
      </template>
    </a-tree>
    <a-empty class="empty-container" :image="emptyImg" v-else />
    <slot>
    </slot>
  </a-spin>
</template>

<script>
import emptyImg from '/static/img/empty.png'
export default {
  name: 'tree',
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    data: {
      default: () => []
    },
    checkable: {
      default: false
    },
    value: {
      default: () => []
    },
    placeholder: {
      default: '请输入关键词'
    },
    replaceFields: {
      default: () => ({})
    },
    showHandle: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      emptyImg,
      searchValue: '',
      name: '',
      editId: '',
      parentId: '',
      loading: false,
      expandedKeys: [],
      treeData: [],
      copyData: [],
      checkedKeyList: []
    }
  },
  created () {
    this.copyData = JSON.parse(JSON.stringify(this.treeData))
  },
  watch: {
    value: {
      handler (newVal, oldVal) {
        this.checkedKeyList = newVal
      },
      immediate: true
    },
    data: {
      handler (newVal, oldVal) {
        this.treeData = newVal
        const changeData = (list) => {
          for (let item of list) {
            this.$set(item, 'scopedSlots', { title: 'custom' })
            if (item.children && item.children.length > 0) {
              changeData(item.children)
            } else {
              this.$set(item, 'children', [])
            }
          }
        }
        changeData(this.treeData)
      },
      immediate: true
    }
  },
  methods: {
    handleSearch (e) {
      const value = this.searchValue
      // 查询item中是否存在value，存在返回层级
      function findValueDeepth (item, value, depIndex = 0) {
        let isInclude = false
        let deepth = 0
        function isIncludeValue (item, value, depIndex) {
          // 存在改变层级
          if (((item.name && item.name.includes(value))) || (item.label && item.label.includes(value))) {
            isInclude = true
            deepth = depIndex
          }
          if (item.children && item.children.length > 0) {
            for (let i of item.children) {
              isIncludeValue(i, value, depIndex + 1)
            }
          }
        }
        isIncludeValue(item, value, depIndex)
        return {
          isInclude,
          deepth
        }
      }
      function getTreeDataByValue (list, value) {
        for (let index = 0; index < list.length; index++) {
          let item = list[index]
          // 如果不存在value
          if (!findValueDeepth(item, value).isInclude) {
            // 删除自身，重新递归list
            list.splice(index, 1)
            getTreeDataByValue(list, value)
            break
          } else if (!item.name.includes(value)) {
            if (item.children && item.children.length > 0) {
              getTreeDataByValue(item.children, value)
            }
          }
        }
      }
      this.treeData = JSON.parse(JSON.stringify(this.data))
      getTreeDataByValue(this.treeData, value)
      // 展开所有节点
      function openTree (list, expandedKeys = []) {
        for (let item of list) {
          expandedKeys.push(item.id || item.key)
          if (item.children && item.children.length > 0) {
            openTree(item.children, expandedKeys)
          }
        }
      }
      this.expandedKeys = []
      openTree(this.treeData, this.expandedKeys)
    },
    handleNodeClick (value, e) {
      this.$emit('handleNodeClick', value)
    },
    handleTreeCheck (value) {
      this.$emit('change', value.checked)
    },
    handleExpand (expandedKeys) {
      this.expandedKeys = expandedKeys
    },
    // 点击编辑按钮
    handleEdit (obj) {
      this.name = obj.name
      this.editId = obj.id
    },
    /** 更新或新增
     * 根据editId判断更新或新增
     * @type '1':拖动改变
     */
    handleCheck (type) {
      if (!this.name.trim() && type !== '1') {
        this.$message.warning('请输入名称')
        return
      }
      this.$emit('handle', this.treeData)
      this.editId = ''
    },
    // input改变
    onChangeItem (e, item) {
      let data = this.$getDataByValue(this.treeData, 'id', item.id)
      this.$set(data, 'name', this.name)
    },
    // 失去焦点
    handleCancel () {
      this.editId = ''
      this.handleDeleteNull(this.treeData, 'id', '')
    },
    // 删除value为空的对象
    handleDeleteNull (list, field, value) {
      for (const index in list) {
        const item = list[index]
        if (item[field] === value) {
          list.splice(index, 1)
          return
        }
        if (item.children && item.children.length > 0) {
          this.handleDeleteNull(item.children, field, value)
        }
      }
    },
    // 获取parent
    getParent (list, id, parent = {}) {
      let parentItem
      function getItem (list, id, parent) {
        for (let item of list) {
          if (item.id === id) {
            parentItem = parent
            return
          }
          if (item.children && item.children.length > 0 && !parentItem) {
            getItem(item.children, id, item)
          }
        }
      }
      getItem(list, id, parent)
      return parentItem
    },
    /**
     * @type '0':添加同级;'1':添加子级
     * @item 当前操作对象
     */
    handleAdd (type, item) {
      this.name = ''
      const params = {
        name: '',
        id: '',
        scopedSlots: {
          title: 'custom'
        }
      }
      if (type === '1') {
        const expandedKeys = [...this.expandedKeys, item.id]
        this.expandedKeys = [...new Set(expandedKeys)]
        this.parentId = item.id
        if (!item.children) {
          let result = this.$getDataByValue(this.treeData, 'id', item.id)
          result.children = [params]
          return
        }
        item.children.unshift(params)
      } else {
        let parent = this.getParent(this.treeData, item.id)
        this.parentId = parent.id
        if (Object.keys(parent).length === 0) {
          parent = this.treeData
        } else {
          parent = parent.children
        }
        for (const index in parent) {
          const child = parent[index]
          if (child.id === item.id) {
            parent.splice(+index + 1, 0, params)
            break
          }
        }
      }
    },
    // 删除
    handleDelete (item) {
      this.$emit('handleDelete', item)
    },
    onDragEnter (info) {
      // expandedKeys 需要受控时设置
      // this.expandedKeys = info.expandedKeys
    },
    onDrop (info) {
      const dropKey = info.node.eventKey
      const dragKey = info.dragNode.eventKey
      const dropPos = info.node.pos.split('-')
      const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
      const loop = (data, key, callback) => {
        data.forEach((item, index, arr) => {
          if (item.id === key) {
            return callback(item, index, arr)
          }
          if (item.children) {
            return loop(item.children, key, callback)
          }
        })
      }
      const data = [...this.treeData]
      // Find dragObject
      let dragObj
      loop(data, dragKey, (item, index, arr) => {
        arr.splice(index, 1)
        dragObj = item
      })
      if (!info.dropToGap) {
        // Drop on the content
        loop(data, dropKey, item => {
          item.children = item.children || []
          // where to insert 示例添加到尾部，可以是随意位置
          item.children.push(dragObj)
        })
      } else if (
        (info.node.children || []).length > 0 && // Has children
        info.node.expanded && // Is expanded
        dropPosition === 1 // On the bottom gap
      ) {
        loop(data, dropKey, item => {
          item.children = item.children || []
          // where to insert 示例添加到尾部，可以是随意位置
          item.children.unshift(dragObj)
        })
      } else {
        let ar
        let i
        loop(data, dropKey, (item, index, arr) => {
          ar = arr
          i = index
        })
        if (dropPosition === -1) {
          ar.splice(i, 0, dragObj)
        } else {
          ar.splice(i + 1, 0, dragObj)
        }
      }
      this.treeData = data
      this.handleCheck('1')
    }
  }
}
</script>

<style lang='less'>
.tree-container {
  .empty-container {
    margin-top: 120px;
  }
  .ant-tree {
    color: #666666;
  }
  .ant-card {
    color: #fff;
    background: transparent;
  }
  .ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner {
    background-color: transparent;
    border-color: #d9d9d9;
  }
  .ant-tree-node-content-wrapper {
    width: calc(~'100% - 24px');
  }
  .input-container {
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    .input-contant {
      background: transparent;
      border: 0;
      height: 18px;
      padding-left: 0;
    }
    .ant-input:focus {
      border: 0;
      box-shadow: none;
      /* border-right-width: 1px !important; */
      outline: 0;
      /* box-shadow: 0 0 0 2px rgb(37 168 167 / 20%); */
    }
  }
  .icon-container {
    display: none;
  }
  ul
    > li[role='treeitem']
    > .ant-tree-node-content-wrapper:hover
    .icon-container {
    display: inline-block;
  }
}
</style>
